﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GomokuCore
{
    public class Game
    {
        public const int BoardSize = 15;

        public GameMode Mode;

        public Player CurrentPlayer;

        public Player BlackPlayer;
        public Player WhitePlayer;

        public PositionStatus[,] Board = new PositionStatus[BoardSize, BoardSize];

        public Game(GameMode mode, Player blackPlayer, Player whitePlayer)
        {
            Mode = mode;
            BlackPlayer = blackPlayer;
            WhitePlayer = whitePlayer;

            CurrentPlayer = BlackPlayer;
        }

        public void Move(Position pos)
        {
            Board[pos.Row, pos.Col] = CurrentPlayer.Color;

            CurrentPlayer = CurrentPlayer.Color == PositionStatus.Black ? WhitePlayer : BlackPlayer;
        }

        public GameStatus GetVictoryStatus()
        {
            GameStatus status = GameStatus.InProgress;

            // Left ~ Right
            status = GetVictoryStatus(new Position(0, 0), pos => pos.Offset(1, 0), pos => pos.Offset(0, 1));
            if (status != GameStatus.InProgress)
                return status;

            // Top ~ Bottom
            status = GetVictoryStatus(new Position(0, 0), pos => pos.Offset(0, 1), pos => pos.Offset(1, 0));
            if (status != GameStatus.InProgress)
                return status;

            // BottomLeft ~ TopRight
            status = GetVictoryStatus(new Position(Game.BoardSize - 1, 0), pos => pos.Row > 0 ? pos.Offset(-1, 0) : pos.Offset(0, 1), pos => pos.Offset(1, 1));
            if (status != GameStatus.InProgress)
                return status;

            // TopLeft ~ BottomRight
            status = GetVictoryStatus(new Position(0, 0), pos => pos.Row < Game.BoardSize - 1 ? pos.Offset(1, 0) : pos.Offset(0, 1), pos => pos.Offset(-1, 1));
            if (status != GameStatus.InProgress)
                return status;

            for (int row = 0; row < BoardSize; row++)
            {
                for (int col = 0; col < BoardSize; col++)
                {
                    if (Board[row, col] == PositionStatus.Empty)
                        return GameStatus.InProgress;
                }
            }

            return GameStatus.Draw;
        }

        private GameStatus GetVictoryStatus(Position startPos, Func<Position, Position> nextRow, Func<Position, Position> nextCol)
        {
            Position rowStart = startPos;
            while (true)
            {
                var last = PositionStatus.Invalid;
                int count = 0;

                Position pos = rowStart;
                while (true)
                {
                    if (last != Board[pos.Row, pos.Col] && count == 5)
                    {
                        if (last == PositionStatus.Black)
                            return GameStatus.BlackWin;
                        else if (last == PositionStatus.White)
                            return GameStatus.WhiteWin;
                    }

                    if (Board[pos.Row, pos.Col] == PositionStatus.Black || Board[pos.Row, pos.Col] == PositionStatus.White)
                    {
                        if (last == Board[pos.Row, pos.Col])
                        {
                            count++;
                        }
                        else
                        {
                            count = 1;
                        }
                    }

                    last = Board[pos.Row, pos.Col];

                    pos = nextCol(pos);

                    if (pos == Position.Null)
                        break;
                }

                rowStart = nextRow(rowStart);

                if (rowStart == Position.Null)
                    break;
            }

            return GameStatus.InProgress;

        }
    }
}
